﻿using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine.UI;

namespace UIFramework.Editor
{
    public class SpawnUIScripts
    {
        public struct UIElementData
        {
            public string elementName;
            public string typeName;
            public string path;
        }
        public struct BtnEvntData
        {
            public string btnName;
            public string evntName;
        }
        const string BOM_UTF8 = "\uFEFF";
        static string targetDir = Application.dataPath + "/_UI/Output/";
        static string UIName = "";
        const string targetFileExt = ".cs";
        const string defaultElementNameFormat = "{0}_{1}";
        public static List<UIElementData> UIElementDatas = new List<UIElementData>();

        static void Initialize()
        {
            Debug.Log("Start to spawn UI...");
        }
        static void Uninitialize()
        {
            UIElementDatas.Clear();
            Debug.Log("End to spawn UI!!!");
        }
        //生成UI
        [MenuItem("UITools/Spawn UIBase+UI")]
        static void SpawnUI()
        {
            Uninitialize();
            Initialize();
            if (!Directory.Exists(targetDir))
                Directory.CreateDirectory(targetDir);

            if (Selection.activeGameObject == null)
                return;
            GameObject goRoot = Selection.activeGameObject;

            UIName = goRoot.name;
            if (UIName.EndsWith("UI"))
            {
                UIName = UIName.Substring(0, UIName.Length - 2);
            }
            else
            {
                goRoot.name = goRoot.name + "UI";
                Debug.unityLogger.LogWarning("Myx", "Please add the letter 'UI' in the end for UI view. Check the prefab if the gameObject has been add 'UI' here. ");
            }
            string outputPath = targetDir + UIName + "{0}" + targetFileExt;
            string outputPathUI = string.Format(outputPath, "UI");
            string outputPathUIBase = string.Format(outputPath, "UIBase");
            SpawnViewUIBase(goRoot, outputPathUIBase);
            SpawnViewUI(outputPathUI);
            AssetDatabase.Refresh();
            Uninitialize();
        }
        //生成UI
        [MenuItem("UITools/Spawn UIBase")]
        static void SpawnUIBase()
        {
            Uninitialize();
            Initialize();
            if (!Directory.Exists(targetDir))
                Directory.CreateDirectory(targetDir);

            if (Selection.activeGameObject == null)
                return;
            GameObject goRoot = Selection.activeGameObject;

            UIName = goRoot.name;
            if (UIName.EndsWith("UI"))
            {
                UIName = UIName.Substring(0, UIName.Length - 2);
            }
            else
            {
                goRoot.name = goRoot.name + "UI";
                Debug.unityLogger.LogWarning("Myx", "Please add the letter 'UI' in the end for UI view. Check the prefab if the gameObject has been add 'UI' here. ");
            }
            string outputPath = targetDir + UIName + "{0}" + targetFileExt;
            string outputPathUI = string.Format(outputPath, "UI");
            string outputPathUIBase = string.Format(outputPath, "UIBase");
            SpawnViewUIBase(goRoot, outputPathUIBase);
            AssetDatabase.Refresh();
            Uninitialize();
        }
        //生成UI
        [MenuItem("UITools/Spawn UIItem")]
        static void SpawnUIItem()
        {
            Uninitialize();
            Initialize();
            if (!Directory.Exists(targetDir))
                Directory.CreateDirectory(targetDir);

            if (Selection.activeGameObject == null)
                return;
            GameObject goRoot = Selection.activeGameObject;

            UIName = goRoot.name;
            string outputPath = targetDir + UIName + targetFileExt;
            SpawnViewItem(goRoot, outputPath);
            AssetDatabase.Refresh();
            Uninitialize();
        }
        [MenuItem("UITools/Clear Tag(include children)")]
        static void ClearTag()
        {
            GameObject[] go = Selection.gameObjects;
            for (int i = 0; i < go.Length; i++)
            {
                ClearTagRecursive(go[i].transform);
            }

        }
        static string emptyTag = "Untagged";
        static void ClearTagRecursive(Transform trans)
        {
            if (!trans.gameObject.CompareTag(emptyTag))
            {
                trans.gameObject.tag = emptyTag;
            }
            if (trans.childCount > 0)
            {
                for (int i = 0; i < trans.childCount; i++)
                {
                    ClearTagRecursive(trans.GetChild(i));
                }
            }
        }

        //生成UI脚本
        static void SpawnViewUIBase(GameObject goRoot, string outputPath)
        {
            string outputText;
            string path = "";
            AddObjPathAndName(goRoot.transform, "");
            StringBuilder sbVar = new StringBuilder();
            sbVar.Append(BOM_UTF8);
            sbVar.Append("using UnityEngine;\r\n");
            sbVar.Append("using UnityEngine.UI;\r\n");
            sbVar.Append("\r\n");
            sbVar.Append(string.Format("public class {0}UIBase : UIBase\r\n", UIName));
            sbVar.Append("{\r\n");
            sbVar.Append("    public Transform Tran_UIRoot;\r\n");
            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                sbVar.Append(string.Format("    public {0} {1};\r\n", UIElementDatas[i].typeName, UIElementDatas[i].elementName));
            }
            sbVar.Append("\r\n");
            sbVar.Append("    protected override void OnInitialize(Transform uiRoot)\r\n");
            sbVar.Append("    {\r\n");
            sbVar.Append("        base.OnInitialize(uiRoot);\r\n");
            sbVar.Append("        Tran_UIRoot = uiRoot;\r\n");
            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                if (UIElementDatas[i].path == UIName)
                {
                    sbVar.Append(string.Format("        {0} = Tran_UIRoot.GetComponent<{1}>();\r\n",
                    UIElementDatas[i].elementName, UIElementDatas[i].typeName));
                }
                else
                {
                    path = UIElementDatas[i].path.Substring(UIElementDatas[i].path.IndexOf(UIName + "UI/") + UIName.Length + 3);
                    if (UIElementDatas[i].typeName == "GameObject")
                    {
                        sbVar.Append(string.Format("        {0} = Tran_UIRoot.Find(\"{1}\").gameObject;\r\n",
                        UIElementDatas[i].elementName, path));
                    }
                    else
                    {
                        sbVar.Append(string.Format("        {0} = Tran_UIRoot.Find(\"{1}\").GetComponent<{2}>();\r\n",
                        UIElementDatas[i].elementName, path, UIElementDatas[i].typeName));
                    }
                }
            }
            sbVar.Append("    }\r\n");
            sbVar.Append("    public override EUICanvas GetUICanvas()\r\n");
            sbVar.Append("    {\r\n");
            sbVar.Append(string.Format("        return EUICanvas.{0};\r\n", GetUICanvasType(goRoot.transform)));
            sbVar.Append("    }\r\n");
            sbVar.Append("}\r\n");
            outputText = sbVar.ToString();
            byte[] outputData = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(outputText));
            File.WriteAllBytes(outputPath, outputData);
            sbVar.Remove(0, sbVar.Length);
        }
        //生成UI脚本
        static void SpawnViewUI(string outputPath)
        {
            StringBuilder sbVar = new StringBuilder();
            sbVar.Append(BOM_UTF8);
            sbVar.Append("using UnityEngine;\r\n");
            sbVar.Append("\r\n");
            sbVar.Append(string.Format("public class {0}UI : {0}UIBase\r\n", UIName));
            sbVar.Append("{\r\n");
            sbVar.Append(string.Format("    public new const string NAME = \"{0}UI\";\r\n", UIName));

            List<BtnEvntData> list = new List<BtnEvntData>();
            List<string> strlist = new List<string>();
            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                if (UIElementDatas[i].typeName == "Button" || UIElementDatas[i].typeName == "UIButton")
                {
                    string funcName = string.Format("BtnEvnt{0}", UIElementDatas[i].elementName.Substring(UIElementDatas[i].elementName.IndexOf("_")));
                    strlist.Add(string.Format("        {0}.onClick.AddListener({1});\r\n", UIElementDatas[i].elementName, funcName));
                    BtnEvntData data = new BtnEvntData();
                    data.btnName = UIElementDatas[i].elementName;
                    data.evntName = funcName;
                    list.Add(data);
                }
            }
            if (list.Count > 0)
            {
                sbVar.AppendLine();
                sbVar.AppendLine("    #region btn events");
                sbVar.Append("    private void BindingBtnEvent()\r\n    {\r\n");
                for (int i = 0; i < strlist.Count; i++)
                {
                    sbVar.Append(strlist[i]);
                }
                sbVar.Append("    }\r\n");
                for (int i = 0; i < list.Count; i++)
                {
                    sbVar.Append(string.Format("    private void {0}()\r\n", list[i].evntName));
                    sbVar.Append("    {\r\n");
                    sbVar.Append("\r\n");
                    sbVar.Append("    }\r\n");
                }
                sbVar.AppendLine("    #endregion");
                sbVar.AppendLine();
                sbVar.AppendLine("    protected override void OnInitialize(Transform uiRoot)");
                sbVar.AppendLine("    {");
                sbVar.AppendLine("        base.OnInitialize(uiRoot);");
                sbVar.AppendLine("        BindingBtnEvent();");
                sbVar.AppendLine("    }");
            }
            sbVar.Append("}\r\n");
            string outputText = sbVar.ToString();
            byte[] outputData = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(outputText));
            File.WriteAllBytes(outputPath, outputData);
            sbVar.Remove(0, sbVar.Length);
        }
        //生成UI脚本
        static void SpawnViewItem(GameObject goRoot, string outputPath)
        {
            string outputText;
            string path = "";
            AddObjPathAndName(goRoot.transform, "");
            StringBuilder sbVar = new StringBuilder();
            sbVar.Append(BOM_UTF8);
            sbVar.AppendLine("using UnityEngine;");
            sbVar.AppendLine("using UnityEngine.UI;");
            sbVar.AppendLine();
            sbVar.AppendLine(string.Format("public class {0}", UIName));
            sbVar.AppendLine("{");

            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                sbVar.Append(string.Format("    public {0} {1};\r\n", UIElementDatas[i].typeName, UIElementDatas[i].elementName));
            }
            sbVar.AppendLine();

            sbVar.AppendLine(string.Format("    public {0}(GameObject go)", UIName));
            sbVar.Append("    {\r\n");
            sbVar.Append("        Transform root = go.transform;\r\n");
            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                if (UIElementDatas[i].path == UIName)
                {
                    sbVar.AppendLine(string.Format("        {0} = root.GetComponent<{1}>();",
                    UIElementDatas[i].elementName, UIElementDatas[i].typeName));
                }
                else
                {
                    path = UIElementDatas[i].path.Substring(UIElementDatas[i].path.IndexOf(UIName + "UI/") + UIName.Length + 2);
                    if (UIElementDatas[i].typeName == "GameObject")
                    {
                        sbVar.AppendLine(string.Format("        {0} = root.Find(\"{1}\").gameObject;",
                        UIElementDatas[i].elementName, path));
                    }
                    else
                    {
                        sbVar.AppendLine(string.Format("        {0} = root.Find(\"{1}\").GetComponent<{2}>();",
                        UIElementDatas[i].elementName, path, UIElementDatas[i].typeName));
                    }
                }
            }
            List<BtnEvntData> list = new List<BtnEvntData>();
            List<string> strlist = new List<string>();
            for (int i = 0; i < UIElementDatas.Count; i++)
            {
                if (UIElementDatas[i].typeName == "Button" || UIElementDatas[i].typeName == "UIButton")
                {
                    string funcName = string.Format("BtnEvt{0}", UIElementDatas[i].elementName.Substring(UIElementDatas[i].elementName.IndexOf("_")));
                    strlist.Add(string.Format("        {0}.onClick.AddListener({1});\r\n", UIElementDatas[i].elementName, funcName));
                    BtnEvntData data = new BtnEvntData();
                    data.btnName = UIElementDatas[i].elementName;
                    data.evntName = funcName;
                    list.Add(data);
                }
            }
            sbVar.AppendLine();
            for (int i = 0; i < strlist.Count; i++)
            {
                sbVar.Append(strlist[i]);
            }
            sbVar.AppendLine("    }");

            if (list.Count > 0)
            {
                sbVar.AppendLine();
                for (int i = 0; i < list.Count; i++)
                {
                    sbVar.Append(string.Format("    private void {0}()\r\n", list[i].evntName));
                    sbVar.Append("    {\r\n");
                    sbVar.Append("\r\n");
                    sbVar.Append("    }\r\n");
                }
            }
            sbVar.AppendLine("}");
            outputText = sbVar.ToString();
            byte[] outputData = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(outputText));
            File.WriteAllBytes(outputPath, outputData);
            sbVar.Remove(0, sbVar.Length);
        }
        //判断写入UI所属canvas
        static string GetUICanvasType(Transform rootTrans)
        {
            string ec = "Middle";
            Canvas pCanvas = rootTrans.GetComponentInParent<Canvas>();
            if (pCanvas == null)
            {
                Debug.unityLogger.LogError("Myx", "The UI gameobject is not a right child of a transform with Canvas. Will return default value");
            }
            else
            {
                if (rootTrans.parent.name == "BottomCanvas") ec = "Bottom";
                else if (rootTrans.parent.name == "TopCanvas") ec = "Top";
            }
            return ec;
        }
        //绑定UI组件
        static bool AddObjPathAndName(Transform vTransform, string vParentPath)
        {
            string tPath = "";
            if (string.IsNullOrEmpty(vParentPath))
            {
                tPath = vTransform.gameObject.name;
            }
            else
            {
                tPath = string.Format("{0}/{1}", vParentPath, vTransform.gameObject.name);
            }
            if (vTransform.tag == UITag.Gobj || vTransform.tag == UITag.All || vTransform.tag == UITag.Nuclear || vTransform.tag == UITag.ExceptGobj)
            {
                string elementNameFormat = defaultElementNameFormat;
                if (vTransform.tag == UITag.Nuclear)
                {
                    string typeName = NuclearJudge.GetNuclearTypeName(vTransform);
                    string shortTypeName = "";
                    UIElementData data = new UIElementData();
                    //判断该组件是否有简称//
                    if (UIShotNameMap.TryGetValue(typeName, out shortTypeName))
                    {
                        data.elementName = string.Format(elementNameFormat, shortTypeName, vTransform.name);
                    }
                    else
                    {
                        data.elementName = string.Format(elementNameFormat, typeName, vTransform.name);
                    }
                    data.typeName = typeName;
                    data.path = tPath;
                    UIElementDatas.Add(data);

                }
                else if (vTransform.tag == UITag.Gobj)
                {
                    UIElementData g = new UIElementData();
                    g.elementName = string.Format(elementNameFormat, "Gobj", vTransform.name);
                    g.typeName = "GameObject";
                    g.path = tPath;
                    UIElementDatas.Add(g);
                }
                else
                {
                    if (vTransform.tag == UITag.All)
                    {
                        UIElementData g = new UIElementData();
                        g.elementName = string.Format(elementNameFormat, "Gobj", vTransform.name);
                        g.typeName = "GameObject";
                        g.path = tPath;
                        UIElementDatas.Add(g);
                    }

                    MonoBehaviour[] components = vTransform.GetComponents<MonoBehaviour>();
                    for (int i = 0; i < components.Length; i++)
                    {
                        MonoBehaviour comp = components[i];
                        string typeName = comp.GetType().Name;
                        string shortTypeName = "";
                        UIElementData data = new UIElementData();

                        //判断该组件是否有简称//
                        if (UIShotNameMap.TryGetValue(typeName, out shortTypeName))
                        {
                            data.elementName = string.Format(elementNameFormat, shortTypeName, comp.name);
                        }
                        else
                        {
                            data.elementName = string.Format(elementNameFormat, typeName, comp.name);
                        }
                        data.typeName = typeName;
                        data.path = tPath;
                        UIElementDatas.Add(data);
                    }
                }
            }

            if (vTransform.childCount == 0)
                return true;
            for (int i = 0; i < vTransform.childCount;)
            {
                if (AddObjPathAndName(vTransform.GetChild(i), tPath))
                {
                    i++;
                    if (string.IsNullOrEmpty(vParentPath))
                        tPath = vTransform.gameObject.name;
                    else
                        tPath = string.Format("{0}/{1}", vParentPath, vTransform.gameObject.name);
                }
            }
            return true;
        }
    }
}